package com.evaluation.security;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CustomerInvalidSessionStrategy implements InvalidSessionStrategy {

	private final String destinationUrl;

	private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
		
	private boolean createNewSession = true;

	public CustomerInvalidSessionStrategy(String invalidSessionUrl) {
		Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
		this.destinationUrl = invalidSessionUrl;
	}

	@Override
	public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException {

		var reqUri = request.getRequestURI();
		
		if (log.isDebugEnabled()) {
			log.debug("Starting new session (if required) and redirecting to '" + this.destinationUrl + "'");
		}
		if (this.createNewSession) {
			request.getSession();
		}
		
		log.info("{}", reqUri);
		
		var isAjax = "XMLHttpRequest".equals( request.getHeader("x-requested-with") );
		if( isAjax ) {
			//response.setStatus( HttpStatus.UNAUTHORIZED.value() );
			
			try( PrintWriter writer = response.getWriter() ) { 
		        writer.write("Login invalid");    
			}
			finally {
				response.flushBuffer();
			}
			
			return;
		}
		
		this.redirectStrategy.sendRedirect(request, response, this.destinationUrl.equals( reqUri ) || "/favicon.ico".equals( reqUri )
				? this.destinationUrl : this.destinationUrl + "?path=" + URLEncoder.encode( reqUri, StandardCharsets.UTF_8 ) );
	}

	/**
	 * Determines whether a new session should be created before redirecting (to avoid
	 * possible looping issues where the same session ID is sent with the redirected
	 * request). Alternatively, ensure that the configured URL does not pass through the
	 * {@code SessionManagementFilter}.
	 * @param createNewSession defaults to {@code true}.
	 */
	public void setCreateNewSession(boolean createNewSession) {
		this.createNewSession = createNewSession;
		log.info("{}", createNewSession);
	}

}
